package com.xiongjie.routerFactory;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.api.contract.openapi3.OpenAPI3RouterFactory;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class RouterFactoryVertx extends AbstractVerticle {

    @Override
    public void start() {
        Router router = Router.router(vertx);

        //1.创建routerfactory
        OpenAPI3RouterFactory.create(vertx, "openapi.yml", ar -> {
            if (ar.succeeded()) {
                OpenAPI3RouterFactory routerFactory = ar.result();

                //2.加载api文件中的路由和权限
                //  权限绑定操作
                routerFactory.addSecurityHandler("oauth2", context -> {
                    try {
                        //获取toekn
                        String authorization = context.request().headers().get(HttpHeaders.AUTHORIZATION);
                        int idx = authorization.indexOf(' ');
                        String md5token=authorization.substring(idx + 1);

                        //解析token
                        String[] segments = md5token.split("\\.");
                        JsonObject accessToken=new JsonObject(new String(Base64.getUrlDecoder().decode(segments[1]), StandardCharsets.UTF_8));

                        //权限对象存入context
                        context.setUser(new SessionUser(accessToken));
                        context.next();
                    } catch (RuntimeException e) {
                        System.out.println(e.getMessage());
                        context.fail(403,e.getCause());
                    }
                });

                // 路由绑定操作
                routerFactory.addHandlerByOperationId("hello", context -> {
                    JsonObject res = new JsonObject().put("result", "normal http request access sucess!!!");
                    context.response().putHeader("content-type", "application/json").end(res.encode());
                });  //无需权限
                routerFactory.addHandlerByOperationId("helloAuth", context -> {
                    context.user().isAuthorized("xiongjie-role", auth -> {
                        if (auth.succeeded()) {
                            if (auth.result()) {
                                JsonObject res = new JsonObject().put("result", "need permission http request access success!!!");
                                context.response().putHeader("content-type", "application/json").end(res.encode());
                            } else {
                                System.out.println("auth resut is true。" + auth.cause());
                                context.fail(auth.cause());
                            }
                        } else {
                            System.out.println("auth resut is false。" + auth.cause());
                            context.fail(auth.cause());
                        }
                    });
                });  //需要权限

                //3.挂载路由工厂到子路由上
                router.mountSubRouter("/xj", routerFactory.getRouter());

                //4.创建httpserver并监听端口
                vertx.createHttpServer()
                        .requestHandler(router)
                        .listen(8888);
            } else {
                System.out.println("加载api文件失败：" + ar.cause());
            }
        });
    }


    /**
     * 模版操作--添加token的解析
     * requiredRealm参数取值为0表示不需要验证，因为令牌必定由生成它的realm发出。担心令牌被伪造吗？
     * 公司项目：requiredRealm参数被写死成0
     */
    public void addOauth2Security(long requiredRealm){
        OpenAPI3RouterFactory.create(vertx, "openapi.yml", ar -> {
            if (ar.succeeded()) {
                OpenAPI3RouterFactory routerFactory = ar.result();

                routerFactory.addSecurityHandler("oauth2", context -> {
                    try {
                        //1.获取toekn
                        String authorization = context.request().headers().get(HttpHeaders.AUTHORIZATION);
                        if (authorization == null) {
                            throw new RuntimeException("Missing authorization header");
                        }
                        int idx = authorization.indexOf(' ');
                        if (idx <= 0) {
                            throw new RuntimeException("Bad authorization header");
                        }
                        if (!authorization.substring(0, idx).equalsIgnoreCase("bearer")) {
                            throw new RuntimeException("Authorization type is not bearer");
                        }
                        String md5token = authorization.substring(idx + 1);


                        //2.解析token
                        String[] segments = md5token.split("\\.");
                        if (segments.length != 3) {
                            throw new RuntimeException("Invalid token");
                        }
                        JsonObject accessToken = new JsonObject(new String(Base64.getUrlDecoder().decode(segments[1]), StandardCharsets.UTF_8));


                        //3.检查token是否合法
                        if (!accessToken.getString("typ", "unknown").equalsIgnoreCase("bearer")) {
                            throw new RuntimeException("Token type is not bearer");
                        }


                        //4.从token中解析出realm
                        String issuer = accessToken.getString("iss");
                        if (issuer == null) {
                            throw new RuntimeException("Missing iss");
                        }
                        int idx2 = issuer.lastIndexOf('/');
                        if (idx2 <= 0) {
                            throw new RuntimeException("Malformed iss");
                        }
                        long realm;
                        try {
                            realm = Long.valueOf(issuer.substring(idx2 + 1));
                        } catch (NumberFormatException e) {
                            throw new RuntimeException("Invalid realm");
                        }
                        if (requiredRealm > 0 && realm != requiredRealm) {
                            throw new RuntimeException("Incorrect realm");
                        }


                        //5.权限对象存入context
                        context.setUser(new SessionUser(accessToken));
                        context.put("user_id", accessToken.getString("sub"));
                        context.put("realm", realm);
                        context.next();
                    } catch (RuntimeException e) {
                        System.out.println(e.getMessage());
                        context.fail(403, e.getCause());
                    }
                });
            }
        });
    }

}
